#include <hypercom.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

void die(const char *format, ...) {
	char buffer[256];
	va_list args;
	va_start(args, format);
	vsprintf(buffer, format, args);
	if(errno > 0) {
		perror(buffer);
	} else {
		fprintf(stderr, buffer);
	}
	va_end(args);
	exit(1);
}

int buildtcp(const int bindport) {
	int sockfd, reuseaddr = 1;
	struct sockaddr_in sockaddr;
	if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		die("hypercom: buildtcp(): could not create the socket\n");
	}
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
	
	bzero((char *) &sockaddr, sizeof(sockaddr));
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_addr.s_addr = INADDR_ANY;
	sockaddr.sin_port = htons(bindport);
	
	if(bindport != 0) {
		if( bind(sockfd, &sockaddr, sizeof(sockaddr)) < 0 ) {
			die("hypercom: buildtcp(): could not bind the port\n");
		}
	}
	
	return sockfd;
}

int nwconnect(const char *addr, const int port) { /* return a socket that connected, or -1 if failed */
	int sockfd;
	sockfd = buildtcp(0);
	struct hostent *server;
	struct sockaddr_in serveraddr; /* what's the difference between sockaddr_in and sockaddr? */
	if(!(server = gethostbyname(addr))) {
		close(sockfd);
		return -1;
	}
	
	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	bcopy(server->h_addr, &serveraddr.sin_addr.s_addr, server->h_length);
	serveraddr.sin_port = htons(port);
	
	if( connect(sockfd, &serveraddr, sizeof(serveraddr)) < 0 ) {
		close(sockfd);
		return -1;
	}
	
	return sockfd;
}

int nwlisten(const int port) {
	int sockfd;
	sockfd = buildtcp(port);
	if( listen(sockfd, SOMAXCONN) < 0 ) {
		return -1;
	}
	return sockfd;
}

int pprintf(int fd, const char *format, ...) {
	char buffer[PACKETF_MAX];
	int result;
	va_list args;
	va_start(args, format);
	vsprintf(buffer, format, args);
	result = write(fd, buffer, strlen(buffer));
	va_end(args);
	return result;
}

int pscanf(int fd, const char *format, ...) {
	char buffer[PACKETF_MAX];
	int result;
	va_list args;
	va_start(args, format);
	result = read(fd, buffer, PACKETF_MAX);
	vsscanf(buffer, format, args);
	va_end(args);
	return result;
}
